I am attempting to abstract out my core objects for a service I am writing to a library. I have all the other artifacts I need straightened out, but unfortunately I cannot find an artifact for #BsonIgnore. I am using #BsonIgnore to ignore some methods that get added to the bson document when they shouldn't, as the implementing service writes these objects to MongoDb.
For context, the service is written using Quarkus, and Mongo objects are handled with Panache:
implementation 'io.quarkus:quarkus-mongodb-panache'
The library I am creating is mostly just a simplistic pojo library, nothing terribly fancy in the Gradle build.
I have found this on Maven Central: https://mvnrepository.com/artifact/org.bson/bson?repo=novus-releases but seems like not a normal release, and doesn't solve the issue.
In case it is useful, here is my code:
#Data
public abstract class Historied {
/** The list of history events */
private List<HistoryEvent> history = new ArrayList<>(List.of());
/**
* Adds a history event to the set held, to the front of the list.
* #param event The event to add
* #return This historied object.
*/
#JsonIgnore
public Historied updated(HistoryEvent event) {
if(this.history.isEmpty() && !EventType.CREATE.equals(event.getType())){
throw new IllegalArgumentException("First event must be CREATE");
}
if(!this.history.isEmpty() && EventType.CREATE.equals(event.getType())){
throw new IllegalArgumentException("Cannot add another CREATE event type.");
}
this.getHistory().add(0, event);
return this;
}
#BsonIgnore
#JsonIgnore
public HistoryEvent getLastHistoryEvent() {
return this.getHistory().get(0);
}
#BsonIgnore
#JsonIgnore
public ZonedDateTime getLastHistoryEventTime() {
return this.getLastHistoryEvent().getTimestamp();
}
}
This is the correct dependency https://mvnrepository.com/artifact/org.mongodb/bson/4.3.3, but check for your specific version
Related
I am following the steps found here to try to add build settings to files in existing Eclipse CDT projects using the LanguageSettingsProvider extension point, but my settings provider doesn't seem to show in the UI, and its methods aren't queried for settings.
I previously succeeded in adding settings to a project using an external settings provider, but I couldn't find a way to add file-specific settings.
I have implemented a subclass of LanguageSettingsSerializableProvider (let's call it MyProvider), and added it to my plugin.xml thus:
<extension
point="org.eclipse.cdt.core.LanguageSettingsProvider">
<provider
class="com.example.MyProvider"
id="MyProvider_id"
name="I would like to see this in the UI">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
</extension>
The class is implemented approximately thus:
public class MyProvider
extends LanguageSettingsSerializableProvider
implements ILanguageSettingsProvider,
IResourceChangeListener,
ILanguageSettingsEditableProvider,
ILanguageSettingsBroadcastingProvider {
/** The ID of this settings provider */
public static final String MY_PROVIDER_ID = "MyProvider_id"; //$NON-NLS-
/**
* Constructor. Initialises super class with appropriate values.
*/
public MyProvider() {
super( MY_PROVIDER_ID , Messages.UiLabel );
}
#Override
public String getId() {
return MY_PROVIDER_ID ;
}
#Override
public String getName() {
return Messages.UiLabel;
}
#Override
public List<ICLanguageSettingEntry> getSettingEntries(ICConfigurationDescription cfgDescription, IResource resource, String languageId) {
//breakpoint on this line that never gets hit...
return super.getSettingEntries( cfgDescription, resource, languageId );
}
...
}
The real implementation contains some other logic to actually create the settings entries, including registering itself as a resource change listener. The resourceChanged code works fine, calls setSettingsEntries, and then serializeSettings. However, getSettingEntries is never called to obtain these settings.
Is there something I'm missing?
My guess is the plugin.xml is lacking something, but I'm not sure what. There are paragraphs of guidance in the various interfaces that the class implements, but one simple working example would be worth more than a thousand words. I've tried looking at the xml for the built-in settings providers (e.g. GCCBuiltinCompilerSettingsMinGW), but they're defined alongside a lot of other parts of CDT, and it's hard to tell which bits are relevant to my use case.
What I ended up doing was:
someMethod {
final IProject myProject = getProjectFromSomewhere();
final ICProjectDescription projDesc = CoreModel.getDefault().getProjectDescription( myProject );
for (ICConfigurationDescription config : projDesc.getConfigurations()) {
try {
ensureMySettingsProvidedFor( (ILanguageSettingsProvidersKeeper) config );
} catch (ClassCastException e) {
logger.log( Level.WARNING, "Unexpected class was not a keeper of language settings:" + config.getClass().getName(), e );
}
}
}
/**
* Will ensure my settings provider is registered as a settings provider for...
* #param settingsKeeper ...the given configuration.
*/
public static void ensureMySettingsProvidedFor(final ILanguageSettingsProvidersKeeper settingsKeeper) {
if (settingsKeeper instanceof CConfigurationDescriptionCache) {
logger.log(Level.SEVERE, "Got non-writable cached settings. We can't update this!! "
+ "How do we get a writeable version?");
return;
}
for ( ILanguageSettingsProvider provider : settingsKeeper.getLanguageSettingProviders() ) {
if (MyProvider.MY_PROVIDER_ID.equals( provider.getId() )) {
return;
}
}
addMyProvider( settingsKeeper );
}
/**
* Adds my language settings provider to the given configuration by means of its ID.
* #param settingsKeeper The existing configuration.
*/
private static void addMyProvider( final ILanguageSettingsProvidersKeeper settingsKeeper ) {
List<String> ids = new ArrayList<String>();
for ( ILanguageSettingsProvider provider : settingsKeeper.getLanguageSettingProviders() ) {
ids.add( provider.getId() );
}
ids.add(MyProvider.MY_PROVIDER_ID);
List<ILanguageSettingsProvider> newProviders = LanguageSettingsManager.createLanguageSettingsProviders( ids.toArray( new String[ids.size()] ) );
settingsKeeper.setLanguageSettingProviders(newProviders);
}
It doesn't feel like the best answer, but it seems to work most of the time.
One problem is knowing when to do this such that it happens for all projects that don't yet have the provider, but doesn't get called repeatedly, or too often.
Another problem is that we sometimes get a CConfigurationDescriptionCache, and then the code can't do anything.
I'm open to better solutions.
I'm using Eclipselink JPA, I have an Entity with a Timestamp field annotated with #Version por optimistic locking.
By default, this sets the entitymanager to use database time, so, if I have to do a batch update it doesn't work properly as it query the database for time each time it wants to do an insert.
How can I change the TimestampLockingPolicy to use LOCAL_TIME?
The class org.eclipse.persistence.descriptors.TimestampLockingPolicy.class has a public method useLocalTime() but I dont know how to use or, from where should I call it.
Found the answer:
first lets create a DescriptorCustomizer
public class LocalDateTimeCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
OptimisticLockingPolicy policy = descriptor.getOptimisticLockingPolicy();
if (policy instanceof TimestampLockingPolicy) {
TimestampLockingPolicy p = (TimestampLockingPolicy) policy;
p.useLocalTime();
}
}
}
then annotate the entity that has the #Version with
#Customizer(LocalDateTimeCustomizer.class)
I have an Entity that pulls it's data from a REST web service. To keep thing consistent with the entities in my app that pull data from the database I have used ORM and overridden the find functions in the repository.
My problem is that ORM seems to demand a database table. When I run doctrine:schema:update it moans about needing an index for the entity then when I add one it creates me a table for the entity. I guess this will be a problem in the future as ORM will want to query the database and not the web service.
So... am I doing this wrong?
1, If I continue to use ORM how can I get it to stop needing the database table for a single entity.
2, If I forget ORM where do I put my data loading functions? Can I connect the entity to a repository without using ORM?
So... am I doing this wrong?
Yes. It doesn't make sense to use the ORM interfaces if you don't really want to use an ORM.
I think the best approach is NOT to think about implementation details at all. Introduce your own interfaces for repositories:
interface Products
{
/**
* #param string $slug
*
* #return Product[]
*/
public function findBySlug($slug);
}
interface Orders
{
/**
* #param Product $product
*
* #return Order[]
*/
public function findProductOrders(Product $product);
}
And implement them with either an ORM:
class DoctrineProducts implements Products
{
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function findBySlug($slug)
{
return $this->em->createQueryBuilder()
->select()
// ...
}
}
or a Rest client:
class RestOrders implements Orders
{
private $httpClient;
public function __construct(HttpClient $httpClient)
{
$this->httpClient = $httpClient;
}
public function findProductOrders(Product $product)
{
$orders = $this->httpClient->get(sprintf('/product/%d/orders', $product->getId()));
$orders = $this->hydrateResponseToOrdersInSomeWay($orders);
return $orders;
}
}
You can even make some methods use the http client and some use the database in a single repository.
Register your repositories as services and use them rather then calling Doctrine::getRepository() directly:
services:
repository.orders:
class: DoctrineOrders
arguments:
- #doctrine.orm.entity_manager
Always rely on your repository interfaces and never on a specific implementation. In other words, always use a repository interface type hint:
class DefaultController
{
private $orders;
public function __construct(Orders $orders)
{
$this->orders = $orders;
}
public function indexAction(Product $product)
{
$orders = $this->orders->findProductOrders($product);
// ...
}
}
If you don't register controllers as services:
class DefaultController extends Controller
{
public function indexAction(Product $product)
{
$orders = $this->get('repository.orders')->findProductOrders($product);
// ...
}
}
A huge advantage of this approach is that you can always change the implementation details later on. Mysql is not good enough for search anymore? Let's use elastic search, it's only a single repository!
If you need to call $product->getOrders() and fetch orders from the API behind the scenes it should still be possible with some help of doctrine's lazy loading and event listeners.
I want to achieve two goals:
I want my model to be loaded every time from the DB when it's in a life-cycle (for every request there will be just one request to the DB)
I want my model to be attached dynamically to the page and that wicket will do all this oreable binding for me
In order to achieve these two goals I came to a conclusion that I need to use both CompoundPropertyModel and LoadableDetachableModel.
Does anyone know if this is a good approach?
Should I do new CompoundPropertyModel(myLoadableDetachableModel)?
Yes, you are right, it is possible to use
new CompoundPropertyModel<T>(new LoadableDetachableModel<T> { ... })
or use static creation (it does the same):
CompoundPropertyModel.of(new LoadableDetachableModel<T> { ... })
that has both features of compound model and lazy detachable model. Also detaching works correctly, when it CompoudPropertyModel is detached it also proxies detaching to inner model that is used as the model object in this case.
I use it in many cases and it works fine.
EXPLANATION:
See how looks CompoundPropertyModel class (I'm speaking about Wicket 1.6 right now):
public class CompoundPropertyModel<T> extends ChainingModel<T>
This mean, CompoundPropertyModel adds the property expression behavior to the ChainingModel.
ChainingModel has the following field 'target' and the constructor to set it.
private Object target;
public ChainingModel(final Object modelObject)
{
...
target = modelObject;
}
This take the 'target' reference to tho object or model.
When you call getObject() it checks the target and proxies the functionality if the target is a subclass of IModel:
public T getObject()
{
if (target instanceof IModel)
{
return ((IModel<T>)target).getObject();
}
return (T)target;
}
The similar functionality is implemented for setObject(T), that also sets the target or proxies it if the target is a subclass of IModel
public void setObject(T object)
{
if (target instanceof IModel)
{
((IModel<T>)target).setObject(object);
}
else
{
target = object;
}
}
The same way is used to detach object, however it check if the target (model object) is detachable, in other words if the target is a subclass if IDetachable, that any of IModel really is.
public void detach()
{
// Detach nested object if it's a detachable
if (target instanceof IDetachable)
{
((IDetachable)target).detach();
}
}
I am working in J2EE 5 using JPA, I have a working solution but I'm looking to clean up the structure.
I am using EntityListeners on some of the JPA objects I am persisting, the listeners are fairly generic but depend on the beans implementing an interface, this works great if you remember to add the interface.
I have not been able to determine a way to tie the EntityListener and the Interface together so that I would get an exception that lead in the right direction, or even better a compile time error.
#Entity
#EntityListener({CreateByListener.class})
public class Note implements CreatorInterface{
private String message;....
private String creator;
....
}
public interface CreatorInterface{
public void setCreator(String creator);
}
public class CreateByListener {
#PrePersist
public void dataPersist(CreatorInterface data){
SUser user = LoginModule.getUser();
data.setCreator(user.getName());
}
}
This functions exactly the way I want it to, except when a new class is created and it uses the CreateByListener but does not implement the CreatorInterface.
When this happens a class cast exception is thrown somewhere deep from within the JPA engine and only if I happen to remember this symptom can I figure out what went wrong.
I have not been able to figure a way to require the interface or test for the presence of the interface before the listener would be fired.
Any ideas would be appreciated.
#PrePersist
public void dataPersist(Object data){
if (!(data instanceof CreatorInterface)) {
throw new IllegalArgumentException("The class "
+ data.getClass()
+ " should implement CreatorInterface");
}
CreatorInterface creatorInterface = (CreatorInterface) data;
SUser user = LoginModule.getUser();
creatorInterface.setCreator(user.getName());
}
This does basically the same thing as what you're doing, but at least you'll have a more readable error message indicating what's wrong, instead of the ClassCastException.